package com.gugee.ins.common.dal.spider;

import com.gugee.common.exception.BizException;
import com.gugee.common.exception.SpiderRetryableException;
import com.gugee.ins.common.constant.RedisKeyConst;
import com.gugee.ins.common.dal.spider.config.SpiderConfig;
import com.gugee.ins.common.model.spider.blogger.*;
import com.xiguaji.boot.retry.RetryableException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.TimeUnit;

/**
 * InsBloggerSpiderClient
 * @author HuangXin
 */
@Slf4j
@Component
public class InsBloggerSpiderClient {
    /**
     * restTemplate
     */
    @Autowired
    RestTemplate restTemplate;

    /**
     * redis
     */
    @Autowired
    RedisTemplate<String,String> redisTemplate;

    /**
     * config
     */
    @Autowired
    SpiderConfig spiderConfig;
    private static final String BIZ_SPIDER_STATUS_ERROR ="BIZ_SPIDER_STATUS_ERROR";
    private static final String URI =". uri:";

    /**
     * 根据uid获取blogger基本信息
     * @param uid
     * @return
     */
    public InsBloggerByIdResponse getInsBloggerByUid(long uid) {
        String uri = spiderConfig.getHost() + "/Ins/UserInfoByUserId?userId={uid}";
        spiderSleep(RedisKeyConst.SPIDER_BLOGGER_BY_ID,spiderConfig.getSpiderUidSleepSecond());
        ResponseEntity<InsBloggerByIdResponse> responseEntity = restTemplate.getForEntity(uri, InsBloggerByIdResponse.class, uid);
        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            throw new BizException(String.format("get insBloggerByUid error. status: %s . msg: %s",
                    responseEntity.getStatusCodeValue(), responseEntity.getBody()),  BIZ_SPIDER_STATUS_ERROR);
        }
        return responseEntity.getBody();
    }

    /**
     * 根据uid获取blogger基本信息
     * @param userName
     * @return
     */
    @Retryable(value = SpiderRetryableException.class, maxAttemptsExpression = "${ins.spider.insBlogger.retry:1}")
    public InsBloggerByUsernameResponse getInsBloggerByUserName(String userName) {
        String uri = spiderConfig.getHost() + "/Ins/UserInfoByUserName?userName={userName}";

        spiderSleep(RedisKeyConst.SPIDER_BLOGGER_BY_USERNAME,spiderConfig.getSpiderSleepSecond());
        ResponseEntity<InsBloggerByUsernameResponse> responseEntity = restTemplate.getForEntity(uri, InsBloggerByUsernameResponse.class, userName);

        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            throw new BizException(String.format("get insBloggerByUserName error. status: %s . msg: %s",
                    responseEntity.getStatusCodeValue(), responseEntity.getBody()),  BIZ_SPIDER_STATUS_ERROR);
        }
        if (responseEntity.getBody() == null || responseEntity.getBody().getGraphql() == null
                || responseEntity.getBody().getGraphql().getUser() == null) {
            throw new SpiderRetryableException("get insBloggerByUserName error, retry times " + spiderConfig.getSpiderRetryTimes() + URI +
                    uri.replace("{userName}", userName));
        }
        return responseEntity.getBody();
    }

    /**
     * 根据uid获取blogger详情
     * @param uid
     * @return
     */
    @Retryable(value = SpiderRetryableException.class, maxAttemptsExpression = "${ins.spider.insBlogger.detail.retry:1}")
    public InsBloggerDetailResponse getInsBloggerDetail(long uid) {
        String uri = spiderConfig.getHost() + "/Ins/AccountDetail?userId={uid}";

        spiderSleep(RedisKeyConst.SPIDER_BLOGGER_DETAIL,spiderConfig.getSpiderDetailSleepSecond());

        ResponseEntity<InsBloggerDetailResponse> responseEntity = restTemplate.getForEntity(uri, InsBloggerDetailResponse.class, uid);

        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            throw new BizException(String.format("get InsBloggerDetail error. status: %s . msg: %s",
                    responseEntity.getStatusCodeValue(), responseEntity.getBody()),  BIZ_SPIDER_STATUS_ERROR);
        }
        if (responseEntity.getBody() == null) {

            throw new SpiderRetryableException("get InsBloggerDetail error, retry times " + spiderConfig.getSpiderBloggerDetailRetryTimes() + URI +
                    uri.replace("{uid}", uid + ""));
        }
        return responseEntity.getBody();
    }

    /**
     * 根据uid获取blogger 关注列表
     * @param userId
     * @param count
     * @param endCursor
     * @return
     */
    @Retryable(value = SpiderRetryableException.class, maxAttemptsExpression = "${ins.spider.insBlogger.following.retry:1}")
    public InsBloggerFollowingResponse getFollowingBloggerByUid(long userId,Integer count,String endCursor) {
        String uri = spiderConfig.getHost() + "/Ins/UserFollowing?userId={userId}";
        if(count != null && count > 0){
            uri += "&count=" + count;
        }
        uri += "&end_cursor={endCursor}";
        spiderSleep(RedisKeyConst.SPIDER_FOLLOWING_BLOGGER,spiderConfig.getSpiderFollowingSleepSecond());

        ResponseEntity<InsBloggerFollowingResponse> responseEntity = restTemplate.getForEntity(uri, InsBloggerFollowingResponse.class, userId,endCursor);

        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            throw new BizException(String.format("get FollowingBlogger error. status: %s . msg: %s",
                    responseEntity.getStatusCodeValue(), responseEntity.getBody()),  BIZ_SPIDER_STATUS_ERROR);
        }
        if (responseEntity.getBody() == null || responseEntity.getBody().getData() == null
                || responseEntity.getBody().getData().getUser() == null
                || responseEntity.getBody().getData().getUser().getEdgeFollow() == null) {
            throw new SpiderRetryableException("get FollowingBlogger error, retry times " + spiderConfig.getSpiderBloggerFollowingRetryTimes() + URI +
                    uri.replace("{userId}", userId + "").replace("{endCursor}",endCursor));
        }
        return responseEntity.getBody();
    }

    /**
     * 根据uid获取blogger 粉丝列表
     * @param userId
     * @param count
     * @param endCursor
     * @return
     */
    @Retryable(value = RetryableException.class, maxAttemptsExpression = "${ins.spider.insBlogger.follower.retry:1}")
    public InsBloggerFollowedResponse getFollowedBloggerByUid(long userId,Integer count,String endCursor) {
        String uri = spiderConfig.getHost() + "/Ins/UserFollowedBy?userId={userId}";
        if(count != null && count > 0){
            uri += "&count=" + count;
        }
        uri += "&end_cursor={endCursor}";

        spiderSleep(RedisKeyConst.SPIDER_FOLLOWED_BLOGGER,spiderConfig.getSpiderFollowerSleepSecond());
        ResponseEntity<InsBloggerFollowedResponse> responseEntity = restTemplate.getForEntity(uri, InsBloggerFollowedResponse.class, userId,endCursor);

        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            throw new BizException(String.format("get FollowedBlogger error. status: %s . msg: %s",
                    responseEntity.getStatusCodeValue(), responseEntity.getBody()),  BIZ_SPIDER_STATUS_ERROR);
        }
        if (responseEntity.getBody() == null || responseEntity.getBody().getData() == null
                || responseEntity.getBody().getData().getUser() == null
                || responseEntity.getBody().getData().getUser().getEdgeFollow() == null) {

            throw new RetryableException("get FollowedBlogger error, retry times " + spiderConfig.getSpiderBloggerFollowerRetryTimes() + URI +
                    uri.replace("{userId}", userId + "").replace("{endCursor}",endCursor));
        }
        return responseEntity.getBody();
    }

    /**
     * 根据uid获取blogger 粉丝列表
     * @return
     */
    @Retryable(value = RetryableException.class, maxAttemptsExpression = "${ins.spider.insBlogger.retry:1}")
    public InsBloggerSuggestedResponse getSuggestBlogger() {
        String uri = spiderConfig.getHost() + "/Ins/SuggestedUsers";

        spiderSleep(RedisKeyConst.SPIDER_SUGGEST_BLOGGER,spiderConfig.getSpiderSleepSecond());
        ResponseEntity<InsBloggerSuggestedResponse> responseEntity = restTemplate.getForEntity(uri, InsBloggerSuggestedResponse.class);

        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            throw new BizException(String.format("get SuggestBlogger error. status: %s . msg: %s",
                    responseEntity.getStatusCodeValue(), responseEntity.getBody()),  BIZ_SPIDER_STATUS_ERROR);
        }
        if (responseEntity.getBody() == null) {

            throw new RetryableException("get SuggestBlogger error, retry times " + spiderConfig.getSpiderRetryTimes() + ".");
        }
        return responseEntity.getBody();
    }

    /**
     * 爬完就睡眠 防止风控
     */
    private void spiderSleep(String redisKey,long ms){
        if(ms > 0) {
            while (isSleep(redisKey,ms)) {
                //睡眠
                try {
                    Thread.sleep(ms);
                } catch (Exception e) {
                    log.error("spider sleep error,msg:{}",e.getMessage());
                }
            }
        }
    }

    private boolean isSleep(String redisKey,long ms){
        return !redisTemplate.opsForValue().setIfAbsent(redisKey, System.currentTimeMillis() + "", ms, TimeUnit.MILLISECONDS);
    }
}
